﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.CSharp;
using System.IO;
using ICSharpCode.Decompiler.ILAst;

namespace devtm.Aop.InternalProcess.Decompiling
{

    /// <summary>
    /// Writes C# code into a TextWriter.
    /// </summary>
    public class TextWriterOutputFormatter2 : IOutputFormatter
    {
        readonly TextWriter textWriter;
        int indentation;
        bool needsIndent = true;
        bool html;
        int offset;
        int cntInline = 0; 

        /// <summary>
        /// Initializes a new instance of the <see cref="TextWriterOutputFormatter2"/> class.
        /// </summary>
        /// <param name="textWriter">The text writer.</param>
        /// <param name="html">if set to <c>true</c> [HTML].</param>
        /// <param name="offset">The offset.</param>
        public TextWriterOutputFormatter2(TextWriter textWriter, bool html, int offset)
        {

            this.html = html;
            this.offset = offset;

            if (textWriter == null)
                throw new ArgumentNullException("textWriter");

            this.textWriter = textWriter;

        }

        public void WriteIdentifier(string ident)
        {
            WriteIndentation();
            textWriter.Write(ident);
        }

        public void WriteKeyword(string keyword)
        {
            WriteIndentation();
            if (html)
                textWriter.Write(@"<span class=""keyWord"">");

            textWriter.Write(keyword);

            if (html)
                textWriter.Write("</span>");

        }

        public void WriteToken(string token)
        {
            WriteIndentation();

            if (html && token.StartsWith("\"") && token.EndsWith("\""))
                textWriter.Write(@"<span class=""text"">");

            textWriter.Write(token);

            if (html && token.StartsWith("\"") && token.EndsWith("\""))
                textWriter.Write(@"</span>");


        }

        public void Space()
        {
            WriteIndentation();
            textWriter.Write(' ');
        }

        public void OpenBrace(BraceStyle style)
        {
            WriteIndentation();
            textWriter.Write(' ');
            textWriter.Write('{');
            Indent();
            NewLine();
        }

        public void CloseBrace(BraceStyle style)
        {
            Unindent();
            WriteIndentation();
            textWriter.Write('}');
        }

        void WriteIndentation()
        {
            if (needsIndent)
            {
                needsIndent = false;
                for (int i = 0; i < indentation; i++)
                {
                    textWriter.Write(html ? "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" : "\t");
                }

            }
        }

        public void NewLine()
        {
            textWriter.WriteLine(html ? "<br />" : "");
            needsIndent = true;
        }

        public void Indent() { indentation++; }

        public void Unindent() { indentation--; }

        public void WriteComment(CommentType commentType, string content)
        {

            WriteIndentation();

            if (html)
                textWriter.Write(@"<span class=""comment"">");            

            switch (commentType)
            {
                case CommentType.SingleLine:
                    textWriter.Write("//");
                    textWriter.WriteLine(content);
                    break;

                case CommentType.MultiLine:
                    textWriter.Write("/*");
                    textWriter.Write(content);
                    textWriter.Write("*/");
                    break;

                case CommentType.Documentation:
                    textWriter.Write("///");
                    textWriter.WriteLine(content);
                    break;
            }

            if (html)
                textWriter.Write("</span>");
        }




        public virtual void StartNode(AstNode node) 
        {

            if (html)
            {
                if (node is SimpleType)
                    textWriter.Write(@"<span class=""simpleType"">");

                if (cntInline == 0 && InLine(node))
                {

                    Start = textWriter.ToString().Length;

                    textWriter.Write(@"<span class=""inLine"">");
                    cntInline++;


                }

            }
            else
            {
                if (cntInline == 0 && InLine(node))
                {
                    Start = textWriter.ToString().Length;                
                    cntInline++;
                }
            }
        }

        public virtual void EndNode(AstNode node) 
        {

            if (html)
            {
                if (cntInline ==1 && InLine(node))
                {

                    End = textWriter.ToString().Length - Start;

                    textWriter.Write("</span>");
                    cntInline--;
                }

                if (node is SimpleType)
                    textWriter.Write("</span>");
            }
            else
            {
                if (cntInline == 1 && InLine(node))
                {
                    End = textWriter.ToString().Length - Start;                   
                    cntInline--;
                }

            }
        }


        private bool InLine(AstNode node)
        {
            foreach (var i2 in node.Annotations)
                if (i2 is List<ILRange>)
                {
                    List<ILRange> ranges = i2 as List<ILRange>;
                    foreach (ILRange range in ranges)
                        if (range.From < offset && range.To > offset)
                            return true;

                }

            return false;

        }


        public int Start { get; set; }

        public int End { get; set; }

    }


}
